use std::{thread, time};
//D-H密码交换
fn is_prime(n: u128) -> bool {
    !(2..(n)).any(|x| n % x == 0)
}
fn max_prime(n: u128) -> u128 {
    let mut num = n;
    while !is_prime(num) {
        num = num - 1;
    }
    num
}
// x^y mod p 如何计算 13^15679 mod 458
fn pow_mod(x: u128, y: u128, p: u128) -> u128 {
    if y == 0 {
        return 1;
    } else {
        let z = pow_mod(x, y / 2, p); //如果y=5_u128, y/2=2
        if y % 2 == 0 {
            return ((z % p) * (z % p)) % p;
        } else {
            return ((((x % p) * (z % p)) % p) * (z % p)) % p;
        }
    }
}

//求p 原始根 的集合,最多产生元根的上限，从小至大
fn generator_primitive_root(p: u128, num: u128) -> Vec<u128> {
    if !is_prime(p) {
        panic!("p:{} is not prime!", p);
    }
    let mut values: Vec<u128> = Vec::new();
    let target = (1..p).map(|x| x).collect::<Vec<u128>>();
    for i in 1..p {
        if values.len() as u128 > num {
            return values;
        }
        let mut temp_value: Vec<u128> = (1..p).map(|y| pow_mod(i, y, p)).collect();
        temp_value.sort();
        if temp_value == target {
            values.push(i);
            //println!("value:{:?}=>{}",temp_value,x);
        }
    }
    println!("元根value:{:?}", values);
    values
}
//求 指数i, 即为b(任意数)的以a为基数的模p的离散对数。
fn dis_log(b: u128, a: u128, p: u128) -> u128 {
    //对于任意数b及素数p的原始根a，可以找到一个唯一的指数i，满足：b=( a ^ i) mod p，其中 0≤i≤p-1
    let data: Vec<u128> = (0..p - 1).filter(|&i| pow_mod(a, i, p) == b).collect();
    println!("dis_log=> i ={:?}", data);
    data[0]
}


// int64_t GeeJoan::E2EE::Common::jenkins_hash(const char *key, size_t len) {
// uint64_t hash, i;
// for (hash = i = 0; i < len; ++i) {
// hash += key[i];
// hash += (hash << 10);
// hash ^= (hash >> 6);
// }
// hash += (hash << 3);
// hash ^= (hash >> 11);
// hash += (hash << 15);
// return hash;
// }

fn jenkins_hash(key :&[u8], len:usize) ->i64 {
    let mut hash:u128 = 0 ;
    for number in (0..len){
        hash += key[number] as u128;
        let mut temp = hash & 0x003F_FFFF_FFFF_FFFF;
        hash += (temp << 10);
        let mut temp = hash & 0xFFFF_FFFF_FFFF_FFC0;
        hash ^= (temp >> 6);
    };
// hash += (hash << 3);
// hash ^= (hash >> 11);
// hash += (hash << 15);
    //18277363496085643202
    //0xFDA63D4316E05FC2
    return hash as i64;
}

fn main() {

    let str = "dadadad".as_bytes();

    let datai64 = jenkins_hash(str , str.len());
    println!("data {}" , datai64);

    let sleep_seconds = time::Duration::from_secs(1000);
    let randnum = 1259_u128; //随机输入一个较大的值
    let max_prime = max_prime(randnum); //求出randnum中最大的质数
    let groups_primitive_root = generator_primitive_root(max_prime, 50); //50个原根
    let G_primitive_root = *&groups_primitive_root[10]; //10为随机取，指取第11个元根集合数据
    let P = max_prime;
    let A_private_key = 14_u128; // no open
    let B_private_key = 39_u128; // no open
    let A_send_to_B_num = pow_mod(G_primitive_root, A_private_key, P);
    let B_send_to_A_num = pow_mod(G_primitive_root, B_private_key, P);
    let A_compute_key_num = pow_mod(B_send_to_A_num, A_private_key, P);
    let B_compute_key_num = pow_mod(A_send_to_B_num, B_private_key, P);
    println!("测试中的参数：");
    println!("max_prime : {:?}",max_prime);
    println!("G_primitive_root : {:?}", G_primitive_root);
    println!("A_send_to_B_num  : {:?}", A_send_to_B_num);
    println!("B_send_to_A_num  : {:?}", B_send_to_A_num);
    println!("A_compute_key_num: {:?}", A_compute_key_num);
    println!("B_compute_key_num: {:?}", B_compute_key_num);

    println!("\n真实环境中的参数：");
    // 真实中的加密参数
    let g: u128 = 113;
    let p: u128 = 2_u128.pow(64) - 1; //巨大的质数
    let a_private_key = 12583; //保密
    let b_private_key = 11258; //保密
    let a_send_to_b_num = pow_mod(g, a_private_key, p);
    let b_send_to_a_num = pow_mod(g, b_private_key, p);
    println!("真实环境中的A发送的值：{}", a_send_to_b_num);
    println!("真实环境中的B发送的值：{}", b_send_to_a_num);
    let a_compute_key_num = pow_mod(b_send_to_a_num, a_private_key, p);
    let b_compute_key_num = pow_mod(a_send_to_b_num, b_private_key, p);
    println!("真实环境中a_compute_key_num:{:?}", a_compute_key_num);
    println!("真实环境中b_compute_key_num:{:?}", b_compute_key_num);

    println!("mod:{}", pow_mod(48_u128, 23_u128, 187));
    thread::sleep(sleep_seconds);
}